package cn.huobi.basic.service.impl;

import cn.huobi.basic.config.BussinessException;
import cn.huobi.basic.constant.BaseConstant;
import cn.huobi.basic.dto.AccountLoginDto;
import cn.huobi.basic.dto.SmsCodeLoginDto;
import cn.huobi.basic.dto.WechatLoginDto;
import cn.huobi.basic.jwt.JwtUtils;
import cn.huobi.basic.jwt.RsaUtils;
import cn.huobi.basic.jwt.UserInfo;
import cn.huobi.basic.service.LoginService;
import cn.huobi.basic.util.AjaxResult;
import cn.huobi.basic.util.HttpUtil;
import cn.huobi.basic.util.MD5Utils;
import cn.huobi.basic.util.StrUtils;
import cn.huobi.system.domain.Menu;
import cn.huobi.system.mapper.MenuMapper;
import cn.huobi.system.mapper.PermissionMapper;
import cn.huobi.user.domain.Logininfo;
import cn.huobi.user.domain.User;
import cn.huobi.user.domain.Wxuser;
import cn.huobi.user.dto.PhoneRegisterDto;
import cn.huobi.user.mapper.LogininfoMapper;
import cn.huobi.user.mapper.UserMapper;
import cn.huobi.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Value("${jwt.rsa.pri}")
    private String privateRsaKey;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MenuMapper menuMapper;

    /**
     * 账号密码登录
     */
    @Override
    public Map<String, Object> accountLogin(AccountLoginDto accountLoginDto) {
        // 判断参数是否为空 注解
        /*
        * 判断账号是否存在
        */
        Logininfo logininfo = logininfoMapper.findByUsername(accountLoginDto.getAccount(),accountLoginDto.getType());
        if (logininfo == null){
            throw new BussinessException("账号或密码错误！");
        }
        /*
        * 判断密码是否正确
        */
        String encrypPassword = MD5Utils.encrypByMd5(logininfo.getSalt() + accountLoginDto.getPassword());
        if (StringUtils.isBlank(encrypPassword) || !encrypPassword.equals(logininfo.getPassword())){
            throw new BussinessException("账号或密码错误!");
        }
        return this.getLogininfo(logininfo);
//        // 生成 token
//        String token = UUID.randomUUID().toString();
//        /*
//        * 将token login 存入redis中
//        */
//        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
//        /*
//         * 去除login中的敏感字符
//         */
//        logininfo.setPassword("");
//        logininfo.setSalt("");
//        logininfo.setPhone("");
//        // 返回前端
//        Map<String, Object> map = new HashMap<>();
//        map.put("token",token);
//        map.put("logininfo",logininfo);
//        return map;
    }

    /**
     * 短信验证码登录
     */
    @Override
    public Map<String, Object> smsCodeLogin(SmsCodeLoginDto smsCodeLoginDto) {
        /*
         * 判断手是否存在
         */
        Logininfo logininfo = logininfoMapper.findByUsername(smsCodeLoginDto.getPhone(), smsCodeLoginDto.getType());
        if(logininfo == null){
            throw new BussinessException("账户不存在！");
        }
        /*
         * 判断验证码是否为空 是否正确
         */
        if(StringUtils.isBlank(smsCodeLoginDto.getSmsCode())){
            throw new BussinessException("验证码不能我空");
        }
        String redisSmsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstant.VerfityCodeCons.LOGIN_SMSCODE_PHONE, smsCodeLoginDto.getPhone()));
        if (StringUtils.isBlank(redisSmsCode) || redisSmsCode.equals(smsCodeLoginDto.getSmsCode())){
            throw new BussinessException("手机号或验证码错误");
        }

        return this.getLogininfo(logininfo);
//        // 生成token
//        String token = UUID.randomUUID().toString();
//        /*
//         * 将token login 存入redis中
//         */
//        redisTemplate.opsForValue().set(token,logininfo,30,TimeUnit.MINUTES);
//        /*
//         * 去除login中的敏感字符
//         */
//        logininfo.setPassword("");
//        logininfo.setSalt("");
//        logininfo.setPhone("");
//        // 返回前端
//        Map<String, Object> map = new HashMap<>();
//        map.put("token",token);
//        map.put("logininfo",logininfo);
//        return map;
    }

    /**
     * 微信扫码登录
     */
    @Override
    public AjaxResult wechatLogin(WechatLoginDto wechatLoginDto) {
        // 判断参数是否为空
        if(StringUtils.isBlank(wechatLoginDto.getCode())){
            throw new BussinessException("参数不能为空！");
        }
        // 调用 微信第二个接口获取 token openId
        Pair<String, String> tokenAndOpenId = this.getTokenAndOpenId(wechatLoginDto.getCode());
        // 根据openId查询 判断用户是否已注册
        Wxuser wxuser = wxuserMapper.findByOpenId(tokenAndOpenId.getRight());
        if (wxuser != null && wxuser.getUserId() != null){
            // 已注册直接登录
            Logininfo logininfo = logininfoMapper.findByUserId(wxuser.getUserId());
            Map<String, Object> map = this.getLogininfo(logininfo);
            return AjaxResult.me().success(map);
        }
        // 未注册返回 nobinder
        StringBuffer noBinder = new StringBuffer();
        noBinder.append("?accessToken=").append(tokenAndOpenId.getLeft())
                .append("&openId=").append(tokenAndOpenId.getRight());
        return AjaxResult.me().fail("noBinder").setResultObj(noBinder);
    }

    /**
     * 手机号绑定
     */
    @Override
    public Map<String, Object> wechatBinder(WechatLoginDto wechatLoginDto) {
        // 判断参数是否为空
        if (StringUtils.isBlank(wechatLoginDto.getPhone())){
            throw new BussinessException("手机号不能为空");
        }
        if (StringUtils.isBlank(wechatLoginDto.getVerifyCode())){
            throw new BussinessException("验证码不能为空");
        }
        if (StringUtils.isBlank(wechatLoginDto.getAccessToken())){
            throw new BussinessException("参数token不能为空");
        }
        if (StringUtils.isBlank(wechatLoginDto.getOpenId())){
            throw new BussinessException("参数openId不能为空");
        }
        // 判断验证码是否正确
        this.verifySmsCode(wechatLoginDto);
        // 调用微信第三个接口获取用户信息
        String getUserUrl = String.format(BaseConstant.WeChatLoginCons.WeChat_LOGIN_USER_INFO,
                wechatLoginDto.getAccessToken(), wechatLoginDto.getOpenId());
        // json字符串转成 实体
        String jsonStr = HttpUtil.httpGet(getUserUrl);
        Wxuser wxuser = JSONObject.parseObject(jsonStr, Wxuser.class);
        // 判断数据库中是否存在
        User user = userMapper.findByPhone(wechatLoginDto.getPhone());
        Logininfo logininfo = new Logininfo();
        if (user == null){
            // 没有 将用户信息保存到数据库中
            user = this.dtoConvertUser(wechatLoginDto);
            logininfo = this.userConvertLogininfo(user);
            logininfoMapper.add(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.add(user);
        }else {
            // 有 获取logininfo对象
            logininfo = logininfoMapper.findById(user.getLogininfoId());
        }
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);
        return this.getLogininfo(logininfo);
    }

    /**
     * 将前端传递过来的 WechatLoginDto 转换为 user
     */
    private User dtoConvertUser(WechatLoginDto dto){
        // 盐值
        String salt = StrUtils.getComplexRandomString(32);
        // 密码
        String password = salt + "1";
        // MD5加密
        String encryp = MD5Utils.encrypByMd5(password);
        return User.builder()
                .username(dto.getPhone())
                .phone(dto.getPhone())
                .salt(salt)
                .password(encryp)
                .state(1)
                .createtime(new Date())
                .build();
    }

    /**
     * 将 user 转换为 logininfo
     */
    private Logininfo userConvertLogininfo(User user){
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);
        return logininfo;
    }

    /**
     * 短信验证码校验
     */
    private void verifySmsCode(WechatLoginDto wechatLoginDto) {
        String redisSmsCode = (String) redisTemplate.opsForValue().get(
                String.format(BaseConstant.VerfityCodeCons.BINDER_SMSCODE_PHONE, wechatLoginDto.getPhone()));
        if (StringUtils.isBlank(redisSmsCode)){
            throw new BussinessException("验证码错误");
        }
        String[] split = redisSmsCode.split(":");
        String smsCode = split[0];
        if (!smsCode.equals(wechatLoginDto.getVerifyCode())){
            throw new BussinessException("验证码错误");
        }
    }

    /**
     * 获取token和openId
     */
    private Pair<String,String> getTokenAndOpenId(String code){
        String tokenUrl = String.format(BaseConstant.WeChatLoginCons.WeChat_LOGIN_TOKEN_URL,
                BaseConstant.WeChatLoginCons.WeChat_LOGIN_APPID, BaseConstant.WeChatLoginCons.WeChat_LOGIN_SECRET,
                code);
        String jsonStr = HttpUtil.httpGet(tokenUrl);
        // 将json字符串转成json对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String accessToken= jsonObject.getString("access_token");
        String openId = jsonObject.getString("openId");
        return Pair.of(accessToken,openId);
    }

    /**
     * jwt方案
     */

    private Map<String,Object> getLogininfo(Logininfo logininfo){
        //使用jwt方案
        PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(privateRsaKey).getFile());
        Map<String, Object> hashMap = new HashMap<>();
        UserInfo user = new UserInfo();
        user.setLogininfo(logininfo);
        if (logininfo.getType() == 0){
            List<String> permissions = permissionMapper.findByLogininfoId(logininfo.getId());
            List<Menu> menus = menuMapper.findByLogininfoId(logininfo.getId());
            user.setPermissions(permissions);
            user.setMenus(menus);
            hashMap.put("permissions", permissions);
            hashMap.put("menus", menus);
        }
        String token = JwtUtils.generateTokenExpireInMinutes(user, privateKey, 120);
        logininfo.setPassword("");
        logininfo.setSalt("");
        logininfo.setPhone("");
        // 返回前端
        hashMap.put("token",token);
        hashMap.put("logininfo",logininfo);
        return hashMap;
    }



//    private Map<String,Object> getLogininfo(Logininfo logininfo){
//        // 生成 token
//        String token = UUID.randomUUID().toString();
//        /*
//         * 将token login 存入redis中
//         */
//        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
//        /*
//         * 去除login中的敏感字符
//         */
//        logininfo.setPassword("");
//        logininfo.setSalt("");
//        logininfo.setPhone("");
//        // 返回前端
//        Map<String, Object> map = new HashMap<>();
//        map.put("token",token);
//        map.put("logininfo",logininfo);
//        return map;
//    }


//    public static void main(String[] args) {
//        String salt = StrUtils.getComplexRandomString(32);
//        System.out.println(salt);
//        String s = MD5Utils.encrypByMd5(salt + 1025844);
//        System.out.println(s);
//    }
}
